Execution environments based on virtual machines are widely used for application programs such as Java or Microsoft .NET that receive programs through the Internet to execute them or that execute programs generated dynamically, after the application has started.
A reason for executing application programs in a virtual machine environment is that this method is appropriate for reading and executing programs after activating the applications (i.e., after the execution) or is appropriate for executing programs on various platforms (hardware or OSs (Operating Systems)) with the virtual machine absorbing platform-dependent processes. By contrast, application programs written in C language, COBOL, or the like are usually converted (compiled) by static compilers into an executable format, which is dependent on the operating platforms, before the execution of the applications.
As execution environments for executing an application program on a virtual machine, there are two methods. One is a method in which an application program is operated by an interpreter (commands in the program are interpreted and executed in a one-by-one manner), while the other is a method in which the program is compiled into native codes (machine instructions), and thereafter those codes are executed. Some execution environments have only one of these methods, while others have both of them.
Execution by interpreters is usually several through several hundred times slower than that by native codes, and programs are usually converted into native codes to be executed. However, conversion into native codes (compilation) is executed when an application program is executed, and thus the execution time of the application includes the time for the compilation process.
In particular, many compilation processes are executed immediately after the activation of an application program, causing a problem whereby the execution performance of the application program is not stable immediately after the activation. Compilation of an application program is executed after the activation (during execution) of the application program, and thus compilers for such compilation are referred to as dynamic compilers or just-in-time compilers.
There are techniques of reducing the influence of the use of dynamic compilers when application programs are executed on virtual machines, examples of which are as below.
The first technique is a method by which the degree of optimization by a dynamic compiler is lowered so as to reduce the loads of compilation processes. Optimization by a compiler is a process of converting output native codes into codes of a higher speed. Powerful optimization can increase the speed of native codes, while at the same time the compilation loads increase. Accordingly, when higher performance is required for activating application programs such as those in a virtual machine for clients, compilers with a light-loaded optimization process are used so as to give priority to performance during activation. By contrast, in an application-server oriented virtual machine, which has to execute many application programs, compilers with reinforced optimization processes are used so as to give priority to an ability to operate at full performance capacity.
For information about Java virtual machines used in the first conventional technique, or the like, refer to http://java.sun.com/j2se/1.5.0/ja/docs/ja/guide/vm/index.html.
The second technique is a method in which adjustment is performed in such a manner that operations at full performance capacity can be achieved while suppressing loads of compilation processes for activation. Compilers based on this method are referred to as adaptive compilers. This type of compiler employs a method in which execution starts as an interpreter at the activation of an application program, and bottlenecks (methods that operate often) for performance are found by analyzing the program during the execution. Methods that may have an influence on performance are compiled while methods that are executed less frequently are not compiled so as to achieve the maximum performance while reducing loads of compilation processes at the activation of application programs.
For information about Java virtual machines used in the second conventional technique, refer to the above web site.
For information about the outline of optimization and compilation of Oracle, JRockit, JDK, and JIT, please refer to http://otndnld.oracle.co.jp/document/products/jrockit/geninfo/diagnos/underst_jit.html.
As a third technique, there is a method in which programs that are frequently used are read and compiled in accordance with information obtained beforehand (obtained, for example, at the previous execution of the application program) after the application program is activated and before inputs into that application program are received (i.e., before starting the service).
As a conventional technique, there is a system that makes it possible to start a process of converting highly frequent methods into native codes in a short time and at the same time to prevent interference in the execution of application programs that might be caused by loads of this conversion.    Patent Document 1: Japanese Laid-open Patent Publication No. 2007-213490
As described above, in an environment of executing application programs on virtual machines, application programs are usually executed after the programs are converted into native codes after the activation of the application programs, by compilers that are referred to as a dynamic compiler or a just-in-time compiler.
Conversion into native codes (compilation) is performed during the execution of application programs, bringing about an inevitable problem wherein the execution time of an application program includes time for compilation.
In particular, there is a problem wherein many compilation processes operate immediately after the activation of an application, causing unstable execution performance of applications immediately after the activation.
FIG. 1 illustrates an example of unstable execution performance immediately after the activation.
The horizontal axis represents a time that has elapsed after the activation of a virtual machine, the right horizontal axis represents a time that an application program requires to process a process request (response time), and the left horizontal axis represents the total number of programs (methods) converted by compilers into native codes. Because not all programs have been converted into native codes (some of the programs are executed by interpreters) and many compilation processes are executed, the processing times are not stable.
In order to cope with this problem, the first conventional technique employs a method in which the degree of optimization by compilers is sacrificed so as to reduce loads of compilation processes. This method is effective in a particular environment such as a client machine. However, because of weakness in optimization by compilers, this method sacrifices the maximum performance of application programs in an environment using a virtual machine for an application server, which is required to operate at the maximum performance capacity. For example, this method is not appropriate for an application program operating on an application server that starts its service at nine o'clock every morning in order to perform a large number of processes from immediately after the activation (online ticket sales for example).
The second technique employs a method in which only highly frequent methods, which become a bottleneck, are compiled. This method is effective in view of performance at the activation of applications compared with a method in which all programs are compiled. However, how many minutes to use for execution by interpreters and an analysis of execution frequencies of programs, and when to execute a compilation process so as to shift to execution based on native codes in order to achieve desired effects depend upon various factors (such as the hardware performance, characteristics of application programs, the amount of processes performed by application programs, etc.). As a method of finding a bottleneck in a program (methods executed highly frequently), a method is known that uses the number of times of calling programs (methods) or the number of loops of programs (methods). However, finding the optimum balance between execution by an interpreter and native-code based execution is very difficult, and a method has conventionally been employed in which balance adjustment is not performed but compilation is performed when the number of times of execution of a program (method) has reached a prescribed number of times. Accordingly, in some cases, the operation requirements are not satisfied by the performance at the activation of an application program even when a virtual machine supported by the second conventional technique is used.
The third conventional technique employs a method in which programs (methods) that are frequently used are read and compiled after the activation of the application and before reception of input into the application program (i.e., before starting services). However, this method is not appropriate to applications that require reading of programs through the Internet during the execution of the application programs or to applications that generate programs after the execution.
In a case where programs are to be read dynamically (read on an as-needed basis) such as a case of Java language, when a method refers to another method and the method to be referred to is still being read, the compiler generates redundant codes.
This is because a code instructing that “if the program has not been read, the program should be read and the reference should be resolved” has to be included in codes generated by compilers. These kinds of codes are often used in the third technique, and accordingly this technique is not appropriate to applications that require reading of programs through the Internet during the execution of the application programs or to applications that generate programs after the execution.
Also, this technique is disadvantageous in view of optimization by compilers. Compilers can perform more powerful optimization by predicting the execution of programs (branching probability by IF statements, and functions called frequently by virtual function call, for example). When programs are read and executed dynamically, dynamic information of programs is collected (profiled) during the execution by an interpreter before compilation, and the optimization by the compiler usually uses this information. However, this optimization cannot be performed if compilation is performed before the execution of programs as in the third conventional technique, and thus this technique is disadvantageous.